/**
 * DateTimeCleaner - 日期时间清洗工具
 * 将各种日期格式统一为 YYYY-MM-DD HH:mm:ss
 */

class DateTimeCleaner {
    /**
     * 清洗日期时间值，统一输出格式
     * @param {string|number|Date} value - 输入值
     * @param {Object} options - 配置选项
     * @param {boolean} options.dateOnly - 是否只返回日期部分
     * @param {boolean} options.timeOnly - 是否只返回时间部分
     * @returns {string|null} 格式化后的日期时间字符串，无法解析返回null
     */
    static clean(value, options = {}) {
        if (value === null || value === undefined || value === '') {
            return null;
        }

        let date = null;

        // 如果是 Date 对象
        if (value instanceof Date) {
            date = value;
        }
        // 如果是数字（可能是Excel序列号或时间戳）
        else if (typeof value === 'number') {
            date = this._parseNumber(value);
        }
        // 如果是字符串
        else if (typeof value === 'string') {
            const trimmed = value.trim();

            // 尝试各种格式解析
            date = this._parseStandardFormat(trimmed)
                || this._parseChineseFormat(trimmed)
                || this._parseCompactFormat(trimmed)
                || this._parseTimestamp(trimmed)
                || this._parseNativeDate(trimmed);
        }

        if (!date || isNaN(date.getTime())) {
            console.warn(`[DateTimeCleaner] Unable to parse: ${value}`);
            return null;
        }

        return this._format(date, options);
    }

    /**
     * 验证日期是否有效
     * @param {string} value - 日期字符串
     * @returns {boolean}
     */
    static isValid(value) {
        return this.clean(value) !== null;
    }

    /**
     * 解析数字（Excel序列号或时间戳）
     */
    static _parseNumber(num) {
        // Excel序列号通常在 1-100000 范围内（约1900-2173年）
        if (num > 0 && num < 100000) {
            // Excel serial number: days since 1899-12-30
            // Excel有一个bug，认为1900年是闰年，所以需要-1
            const excelEpoch = new Date(Date.UTC(1899, 11, 30));
            const days = Math.floor(num);
            const fraction = num - days;

            const ms = excelEpoch.getTime() + (days * 24 * 60 * 60 * 1000) + (fraction * 24 * 60 * 60 * 1000);
            return new Date(ms);
        }
        // 10位时间戳（秒）
        else if (num > 1000000000 && num < 10000000000) {
            return new Date(num * 1000);
        }
        // 13位时间戳（毫秒）
        else if (num > 1000000000000 && num < 10000000000000) {
            return new Date(num);
        }
        return null;
    }

    /**
     * 解析标准格式: YYYY-MM-DD, YYYY/MM/DD, YYYY.MM.DD
     */
    static _parseStandardFormat(str) {
        // 匹配: 2023-11-30 09:30:00, 2023/11/30 9:30, 2023.11.30
        const regex = /^(\d{4})[-\/.](\d{1,2})[-\/.](\d{1,2})(?:\s+(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?)?$/;
        const match = str.match(regex);

        if (match) {
            const [, year, month, day, hour = 0, minute = 0, second = 0] = match;
            return new Date(Date.UTC(
                parseInt(year),
                parseInt(month) - 1,
                parseInt(day),
                parseInt(hour),
                parseInt(minute),
                parseInt(second)
            ));
        }
        return null;
    }

    /**
     * 解析中文格式: 2023年11月30日 09时30分00秒
     */
    static _parseChineseFormat(str) {
        // 匹配: 2023年11月30日 09时30分00秒
        const regex = /^(\d{4})年(\d{1,2})月(\d{1,2})日(?:\s*(\d{1,2})时(\d{1,2})分(?:(\d{1,2})秒)?)?$/;
        const match = str.match(regex);

        if (match) {
            const [, year, month, day, hour = 0, minute = 0, second = 0] = match;
            return new Date(Date.UTC(
                parseInt(year),
                parseInt(month) - 1,
                parseInt(day),
                parseInt(hour),
                parseInt(minute),
                parseInt(second)
            ));
        }
        return null;
    }

    /**
     * 解析紧凑格式: 20231130, 20231130093000
     */
    static _parseCompactFormat(str) {
        // 8位数字: YYYYMMDD
        if (/^\d{8}$/.test(str)) {
            const year = parseInt(str.substring(0, 4));
            const month = parseInt(str.substring(4, 6));
            const day = parseInt(str.substring(6, 8));

            if (this._isValidDate(year, month, day)) {
                return new Date(Date.UTC(year, month - 1, day));
            }
        }
        // 14位数字: YYYYMMDDHHmmss
        else if (/^\d{14}$/.test(str)) {
            const year = parseInt(str.substring(0, 4));
            const month = parseInt(str.substring(4, 6));
            const day = parseInt(str.substring(6, 8));
            const hour = parseInt(str.substring(8, 10));
            const minute = parseInt(str.substring(10, 12));
            const second = parseInt(str.substring(12, 14));

            if (this._isValidDate(year, month, day)) {
                return new Date(Date.UTC(year, month - 1, day, hour, minute, second));
            }
        }
        return null;
    }

    /**
     * 解析字符串形式的时间戳
     */
    static _parseTimestamp(str) {
        // 10位或13位纯数字字符串
        if (/^\d{10}$/.test(str)) {
            return new Date(parseInt(str) * 1000);
        } else if (/^\d{13}$/.test(str)) {
            return new Date(parseInt(str));
        }
        return null;
    }

    /**
     * 使用原生Date解析（最后尝试）
     */
    static _parseNativeDate(str) {
        const date = new Date(str);
        if (!isNaN(date.getTime())) {
            return date;
        }
        return null;
    }

    /**
     * 验证日期有效性
     */
    static _isValidDate(year, month, day) {
        if (year < 1900 || year > 2100) return false;
        if (month < 1 || month > 12) return false;
        if (day < 1 || day > 31) return false;

        // 检查月份天数
        const daysInMonth = new Date(year, month, 0).getDate();
        return day <= daysInMonth;
    }

    /**
     * 格式化日期输出
     */
    static _format(date, options = {}) {
        const y = date.getUTCFullYear();
        const m = String(date.getUTCMonth() + 1).padStart(2, '0');
        const d = String(date.getUTCDate()).padStart(2, '0');
        const h = String(date.getUTCHours()).padStart(2, '0');
        const mi = String(date.getUTCMinutes()).padStart(2, '0');
        const s = String(date.getUTCSeconds()).padStart(2, '0');

        if (options.dateOnly) {
            return `${y}-${m}-${d}`;
        }
        if (options.timeOnly) {
            return `${h}:${mi}:${s}`;
        }

        // 如果时间全为0，只返回日期
        if (h === '00' && mi === '00' && s === '00') {
            return `${y}-${m}-${d}`;
        }

        return `${y}-${m}-${d} ${h}:${mi}:${s}`;
    }
}

module.exports = DateTimeCleaner;
